--[[
-- Author:      feilong
-- DateTime:    2020-10-10 17:19:33
-- Description: 
    开启集群功能
    1集群节点列表的维护
    2接收节点注册
    3接收节点心跳
    4删除断线节点
    5获取指定类型的节点

--]]


local skynet = require "skynet"
local cluster = require "skynet.cluster"


local ClusterManager = class("ClusterManager")

---------------------------------------------------------
-- Private
---------------------------------------------------------
function ClusterManager:ctor(message_dispatch)
	
	self.cluster_center = skynet.getenv("cluster_center")		
    self.server_name = skynet.getenv("server_name")

	self.cluster_list = {} --集群列表
    self.node_list = {} --服务器节点列表
    self.node_time = {}

    self.node_info = nil

	self:register()
end

function ClusterManager:register()
    self.message_dispatch = g.MsgDis()
	self.message_dispatch:register('cluster_heart_req', handler(self,self.cluseterHeartReq))
    self.message_dispatch:register('server_register_req', handler(self, self.registerReq))
end

--打开自己的端口
function ClusterManager:open()	
    local server_config = dofile(skynet.getenv("server_config"))
    self.node_info = server_config.node_info
	self:addNode(self.node_info)
    --打开监听
	cluster.open(self.server_name)

    skynet.fork(function ( ... )
        while true do
            skynet.sleep(500)
            self:keepLife()
        end
    end)
end

--更新集群
function ClusterManager:updateCluster(node_info)
    -- 重新加载集群配置
    local name = node_info.name
    local cluster_addr = node_info.cluster_ip ..":".. node_info.cluster_port
    self.cluster_list[name] = cluster_addr
    
end

-- function ClusterManager:updateClusterList(cluster_list)   
--     for k, v in pairs(cluster_list) do 
-- 	    self.cluster_list[k] = v
-- 	end    
--     cluster.reload(self.cluster_list)
-- end

--返回集群列表
function ClusterManager:getClusterList()
	return self.cluster_list
end

function ClusterManager:addNode(node_info)   
    -- 重新加载集群配置
    -- g.Log():debug(node_info)
    local name = node_info.name
    self.cluster_list[name] = node_info.cluster_ip ..":".. node_info.cluster_port        
    cluster.reload(self.cluster_list)
    
    self.node_list[name] = node_info
    self.node_time[name] = os.time()
end

function ClusterManager:removeNode(node_name)   
    -- 重新加载集群配置
    self.cluster_list[node_name] = nil        
    self.node_list[node_name] = nil        
    cluster.reload(self.cluster_list)
end

--获取服务器信息
function ClusterManager:getNode(name)
    return self.node_list[name]
end

--获取服务器列表
function ClusterManager:getNodeList()
    return self.node_list
end

--获取服务器信息
function ClusterManager:getNodesByType(node_type)    
    local node_list = {}
    for _, v in pairs(self.node_list) do         
        if v.type == node_type then 
            table_insert(node_list, v)
        end
    end    
    return node_list
end

--检查所有节点是否正常连接
function ClusterManager:keepLife()
    for name, v in pairs(self.node_time) do 
        if name ~= self.cluster_center and os.time() - v > 20 then 
            --连接断开
            g.Log():debug("连接断开", name)
            self.node_list[name].enable = false
            if os.time() - v > 60*1 then 
                --超时太久删除该节点
                self.node_time[name] = nil
                self.node_list[name] = nil
                self.cluster_list[name] = nil
                g.Log():error("删除超时节点", name)
            end
        end
    end
end


---------------------------------------------------------
-- CMD
---------------------------------------------------------
--nodeserver发来的心跳请求
function ClusterManager:cluseterHeartReq(msg_data)
	-- g.Log():debug("_____2222222____cluseterHeartReq______", msg_data)
    local node_name = msg_data.name    
    self.node_time[node_name] = os.time()

	return true
end


--收到别的服务器注册
function ClusterManager:registerReq(data)
    g.Log():debug("_________收到服务器注册______",data)
    --注册信息有问题
    if not data or not data.id or data.id <= 0 then 
        g.Log():error("__服务器注册失败_id设置不正确_", data)
        return 
    end    

    self:addNode(data)
    
    --通知各个服务器更新集群列表
    for k, v in pairs(self.cluster_list) do 
        if k ~= self.node_info.name then 
            g.Message():callNodeManager(k, "cluster_update_nt", g.cluster_manager:getNodeList())
        end
    end
        
    return true
end

return ClusterManager